package com.chenjt.juc.ten_ThreadLocal;


import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

class MyObject{

    // 这个方法一般不用复写，这里只是为了教学做案例说明
    @Override
    protected void finalize() throws Throwable {
        // finalize的通常目的是在对象被不可撤销地丢弃之前执行的清理操作
        System.out.println("---- invoke finalize method~!!!");
    }
}

/**
 * 注释：
 *
 * @author chenjt
 * @date 2024/7/16 9:30
 */
public class ReferenceDemo {

    public static void main(String[] args) {

//        strongReference();
//        softReference();
//        weakReference();

        MyObject myObject = new MyObject();
        ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();
        PhantomReference<MyObject> phantomReference = new PhantomReference<>(myObject, referenceQueue);
//        System.out.println(phantomReference.get());

        List<byte[]> list = new ArrayList<>();

        new Thread(()->{
            while (true){
                list.add(new byte[1*1024*1024]);
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(phantomReference.get()+"\t" + "list add ok");
            }
        },"t1").start();

        new Thread(()->{
            while (true){
                Reference<? extends MyObject> reference = referenceQueue.poll();
                if(reference != null){
                    System.out.println("---- 有虚对象回收加入了队列");
                    break;
                }
            }
        },"t2").start();


    }

    /**
     * 弱引用（不管内存是否足够，gc运行时就会回收对象占用的内存）
     * 例子说明了gc一运行，对象就会被回收
     */
    private static void weakReference() {
        WeakReference<MyObject> weakReference = new WeakReference<>(new MyObject());
        System.out.println("---- gc before 内存够用：" + weakReference.get());

        System.gc();
        // 等待gc启动
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("---- gc after 内存够用：" + weakReference.get());


    }

    /**
     * 软引用（内存够时不回收，内存不够时会回收）
     * 这个例子限制了JVM的运行内存为10M，单使用超过10M时，会被回收对象MyObject
     */
    private static void softReference() {
        SoftReference softReference = new SoftReference<>(new MyObject());
//        System.out.println("---- softReference:" + softReference.get());

        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("---- gc after内存够用：" + softReference.get());

        try {
            byte[] bytes = new byte[20 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("---- gc after内存不够：" + softReference.get());
        }
    }

    /**
     * 强引用（只有在对象置为null时，gc才会去回收，不然就算内存不足了，也不会去回收这个占用的内存）
     * 只要对象被回收了，就会执行 MyObject.finalize()
     */
    private static void strongReference() {

        MyObject myObject = new MyObject();
        System.out.println("gc before:" + myObject);

        myObject = null;
        System.gc();// 人工开启GC，一般不用

        // 暂停一下，等gc执行，因为调用gc时，不会立刻就启用
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("gc after:" + myObject);

    }

}
